# DDLTableGenerator.java

    package org.codefilarete.stalactite.sql.ddl;

    import java.util.HashMap;

    import org.codefilarete.stalactite.query.builder.DMLNameProvider;
    import org.codefilarete.stalactite.sql.DMLNameProviderFactory;
    import org.codefilarete.stalactite.sql.ddl.structure.Column;
    import org.codefilarete.stalactite.sql.ddl.structure.ForeignKey;
    import org.codefilarete.stalactite.sql.ddl.structure.Index;
    import org.codefilarete.stalactite.sql.ddl.structure.PrimaryKey;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.ddl.structure.UniqueConstraint;
    import org.codefilarete.tool.StringAppender;

    /**
     * @author Guillaume Mary
     */
    public class DDLTableGenerator {

    	private final SqlTypeRegistry typeMapping;

    	protected final DMLNameProvider dmlNameProvider;

    	private DDLTableGenerator(SqlTypeRegistry typeMapping, DMLNameProvider dmlNameProvider) {
    		this.typeMapping = typeMapping;
    		this.dmlNameProvider = dmlNameProvider;
    	}

    	public DDLTableGenerator(SqlTypeRegistry typeMapping, DMLNameProviderFactory dmlNameProviderFactory) {
    		this(typeMapping, dmlNameProviderFactory.build(new HashMap<>()));
    	}

    	public String generateCreateTable(Table<?> table) {
    		DDLAppender sqlCreateTable = new DDLAppender(dmlNameProvider, "create table ", table, "(");
    		for (Column<?, ?> column : table.getColumns()) {
    			generateCreateColumn(column, sqlCreateTable);
    			sqlCreateTable.cat(", ");
    		}
    		sqlCreateTable.cutTail(2);
    		if (table.getPrimaryKey() != null) {
    			generateCreatePrimaryKey(table.getPrimaryKey(), sqlCreateTable);
    		}
    		sqlCreateTable.cat(")");
    		return sqlCreateTable.toString();
    	}

    	protected void generateCreatePrimaryKey(PrimaryKey<?, ?> primaryKey, DDLAppender sqlCreateTable) {
    		sqlCreateTable.cat(", primary key (")
    			.ccat(primaryKey.getColumns(), ", ")
    			.cat(")");
    	}

    	protected void generateCreateColumn(Column<?, ?> column, DDLAppender sqlCreateTable) {
    		sqlCreateTable.cat(column, " ", getSqlType(column))
    				.catIf(Boolean.FALSE.equals(column.isNullable()), " not null");
    	}

    	protected String getSqlType(Column<?, ?> column) {
    		return typeMapping.getTypeName(column);
    	}

    	public String generateCreateIndex(Index<?> index) {
    		Table<?> table = index.getTable();
    		StringAppender sqlCreateIndex = new DDLAppender(dmlNameProvider, "create")
    				.catIf(index.isUnique(), " unique")
    				.cat(" index ", index.getName(), " on ", table, "(")
    				.ccat(index.getColumns(), ", ");
    		return sqlCreateIndex.cat(")").toString();
    	}

    	public String generateCreateForeignKey(ForeignKey<?, ?, ?> foreignKey) {
    		Table<?> table = foreignKey.getTable();
    		StringAppender sqlCreateFK = new DDLAppender(dmlNameProvider, "alter table ", table)
    				.cat(" add constraint ", foreignKey.getName(), " foreign key(")
    				.ccat(foreignKey.getColumns(), ", ")
    				.cat(") references ", foreignKey.getTargetTable(), "(")
    				.ccat(foreignKey.getTargetColumns(), ", ");
    		return sqlCreateFK.cat(")").toString();
    	}

    	public String generateCreateUniqueConstraint(UniqueConstraint<?> uniqueConstraint) {
    		Table<?> table = uniqueConstraint.getTable();
    		StringAppender sqlCreateIndex = new DDLAppender(dmlNameProvider, "alter table ")
    				.cat(table, " add constraint ", uniqueConstraint.getName(), " unique ", "(")
    				.ccat(uniqueConstraint.getColumns(), ", ");
    		return sqlCreateIndex.cat(")").toString();
    	}

    	public String generateAddColumn(Column<?, ?> column) {
    		DDLAppender addColumnStatement = new DDLAppender(dmlNameProvider, "alter table ", column.getTable(), " add column ", column, " ", getSqlType(column));
    		return addColumnStatement.toString();
    	}

    	public String generateDropTable(Table<?> table) {
    		DDLAppender dropTableStatement = new DDLAppender(dmlNameProvider, "drop table ", table);
    		return dropTableStatement.toString();
    	}

    	public String generateDropTableIfExists(Table<?> table) {
    		DDLAppender dropTableStatement = new DDLAppender(dmlNameProvider, "drop table if exists ", table);
    		return dropTableStatement.toString();
    	}

    	public String generateDropIndex(Index<?> index) {
    		DDLAppender dropIndexStatement = new DDLAppender(dmlNameProvider, "drop index ", index.getName());
    		return dropIndexStatement.toString();
    	}

    	public String generateDropForeignKey(ForeignKey<?, ?, ?> foreignKey) {
    		DDLAppender dropConstraintStatement = new DDLAppender(dmlNameProvider, "alter table ", foreignKey.getTable(), " drop constraint ", foreignKey.getName());
    		return dropConstraintStatement.toString();
    	}

    	public String generateDropColumn(Column<?, ?> column) {
    		DDLAppender dropColumnStatement = new DDLAppender(dmlNameProvider, "alter table ", column.getTable(), " drop column ", column);
    		return dropColumnStatement.toString();
    	}
    }